package com.kclm.xsap.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kclm.xsap.dao.*;
import com.kclm.xsap.entity.*;
import com.kclm.xsap.service.*;
import com.kclm.xsap.utils.exception.RRException;
import com.kclm.xsap.utils.exception.ServiceException;
import com.kclm.xsap.utils.time.ClassTimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

@Slf4j
@Service
public class ReservationRecordServiceImpl extends ServiceImpl<ReservationRecordDao, ReservationRecordEntity> implements ReservationRecordService {

    @Autowired
    private ScheduleRecordDao scheduleRecordDao;
    @Autowired
    private GlobalSetDao globalSetDao;
    @Autowired
    private CourseDao courseDao;
    @Autowired
    private MemberBindRecordDao memberBindRecordDao;
    @Autowired
    private ReservationRecordDao reservationRecordDao;
    @Autowired
    private MemberDao memberDao;
    @Autowired
    private CourseCardDao courseCardDao;
    @Autowired
    private ClassRecordDao classRecordDao;

    @Override
    public List<ReservationRecordEntity> selectList(QueryWrapper<ReservationRecordEntity> wrapper) {
        return baseMapper.selectList(wrapper);

    }

    @Override
    public LocalDateTime getReserveTime(Long scheduleId) {
        return baseMapper.selectReserveTime(scheduleId);
    }

    @Override
    public boolean isCancel(Long reserveId) {
        GlobalReservationSetEntity globalReservationSetEntity = globalSetDao.selectById(1);
        ScheduleRecordEntity scheduleRecordEntity = scheduleRecordDao.selectById(reservationRecordDao.selectById(reserveId).getScheduleId());
        LocalDateTime classStartTime = LocalDateTime.of(scheduleRecordEntity.getStartDate(), scheduleRecordEntity.getClassTime());
        if (globalReservationSetEntity.getAppointmentCancelMode() == 1) {
            return true;
        } else if (globalReservationSetEntity.getAppointmentCancelMode() == 2) {
            LocalDateTime cancelEndTime = classStartTime.minusHours(globalReservationSetEntity.getCancelHour());
            System.out.println("取消预约时间" + LocalDateTime.now());
            System.out.println("取消预约截至时间" + cancelEndTime);
            if (LocalDateTime.now().isBefore(cancelEndTime)) {
                return true;
            } else {
                return false;
            }
        } else {
            LocalTime fixedTime = globalReservationSetEntity.getCancelTime();
            LocalDateTime cancelEndTime = classStartTime.minusDays(globalReservationSetEntity.getCancelDay())
                    .withHour(fixedTime.getHour())
                    .withMinute(fixedTime.getMinute())
                    .withSecond(fixedTime.getSecond());
            System.out.println("取消预约时间" + LocalDateTime.now());
            System.out.println("取消预约截至时间" + cancelEndTime);
            if (LocalDateTime.now().isBefore(cancelEndTime)) {
                return true;
            } else {
                return false;
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)//sql语句回滚
    public void isCanInfo(Long reserveId) throws RRException {
        //reservation更新取消次数+1
        ReservationRecordEntity reservationRecordEntity = reservationRecordDao.selectById(reserveId);
        try {
            reservationRecordEntity.setCancelTimes(reservationRecordEntity.getCancelTimes() + 1);
            reservationRecordDao.updateById(reservationRecordEntity);
        } catch (Exception e) {
            throw new ServiceException("更新预约课程记录取消次数失败！");
        }
        //classrecord表更新reserve_check变为1
        try {
            ClassRecordEntity classRecordEntity = classRecordDao.selectOne(new QueryWrapper<ClassRecordEntity>()
                    .eq("member_id", reservationRecordEntity.getMemberId())
                    .eq("schedule_id", reservationRecordEntity.getScheduleId())
                    .eq("bind_card_id", reservationRecordEntity.getCardId()));
            classRecordEntity.setReserveCheck(1);
            classRecordDao.updateById(classRecordEntity);
        } catch (Exception e) {
            throw new ServiceException("更新课程记录预约状态失败！");
        }
        //schedulerecord减去预约人数
        try {
            ScheduleRecordEntity scheduleRecordEntity = scheduleRecordDao.selectById(reservationRecordEntity.getScheduleId());
            scheduleRecordEntity.setOrderNums(scheduleRecordEntity.getOrderNums() - reservationRecordEntity.getReserveNums());
            scheduleRecordDao.updateById(scheduleRecordEntity);
        } catch (Exception e) {
            throw new ServiceException("更新约课人数失败！");
        }
    }

    /**
     * 从以下几个方面判断是否可以预约
     * ////////////////////////////////
     * !!! 最重要的是判断时间是否冲突!!!
     * ///////////////////////////////
     * 1. 上课人数
     * 2. 性别
     * 3. 年龄
     * 4. 卡是否包括该课程
     * 5. 预约次数
     * 6. 提前预约时间是否被限制
     * 7. 会员卡余额和次数是否足够
     */
    @Override
    public void isAdd(ReservationRecordEntity reservationRecordEntity, String startDate) {

        //////////////!!! 最重要的是判断时间是否冲突!!!////////////////////
        isTime(reservationRecordEntity, startDate);
        //////////////////////////////////

        //1. 上课人数
        ScheduleRecordEntity scheduleRecordEntity = scheduleRecordDao.selectById(reservationRecordEntity.getScheduleId());
        System.out.println("课程限制人数：" + courseDao.selectById(scheduleRecordEntity.getCourseId()).getContains());
        System.out.println("已预约人数" + scheduleRecordEntity.getOrderNums());
        System.out.println("正在预约人数：" + reservationRecordEntity.getReserveNums());
        boolean isTrue = courseDao.selectById(scheduleRecordEntity.getCourseId()).getContains() >= scheduleRecordEntity.getOrderNums() + reservationRecordEntity.getReserveNums();
        if (!isTrue) {
            throw new ServiceException("课程人数已满，请选择其它课程！");
        }
        //2. 性别
        CourseEntity courseEntity = courseDao.selectById(scheduleRecordDao.selectById(reservationRecordEntity.getScheduleId()).getCourseId());
        MemberEntity memberEntity = memberDao.selectById(reservationRecordEntity.getMemberId());
        //boolean isSex = courseEntity.getLimitSex().equals(memberEntity.getSex());
        log.error("课程限制性别==========>" + courseEntity.getLimitSex());
        log.error("会员性别==========>" + memberEntity.getSex());

        boolean flag = courseEntity.getLimitSex().equals("无限制");
        if (!flag) {
            if (courseEntity.getLimitSex().equals("男") && memberEntity.getSex().equals("女")) {
                throw new ServiceException("此课程限制【男】!");
                //throw new RRException("此课程限制男性!");
            } else if (courseEntity.getLimitSex().equals("女") && memberEntity.getSex().equals("男")) {
                throw new ServiceException("此课程限制【女】!");
            }
        }
        //3. 年龄
        Period age = Period.between(memberEntity.getBirthday(), LocalDate.now());
        log.info("age==========>" + age);
        log.info("age.getYears()==========>" + age.getYears());
        if (courseEntity.getLimitAge().equals("无限制")) {
        } else {
            int i = Integer.parseInt(courseEntity.getLimitAge());
            if (age.getYears() < i) {
                throw new ServiceException("此课程限制年龄！");
            }
        }
        //卡是否包括该课程
        List<CourseCardEntity> cardEntityList = courseCardDao.selectList(new QueryWrapper<CourseCardEntity>().eq("course_id", scheduleRecordDao.selectById(reservationRecordEntity.getScheduleId()).getCourseId()));
        List<Long> cardIds = new ArrayList<>();
        //找出课程支持的会员卡
        for (CourseCardEntity courseCardEntity : cardEntityList) {
            cardIds.add(courseCardEntity.getCardId());
        }
        MemberBindRecordEntity memberBindRecordEntity = memberBindRecordDao.selectById(reservationRecordEntity.getCardId());
        System.out.println("支持的会员卡ID：" + cardIds);
        System.out.println("当前选择的会员卡Id:" + memberBindRecordEntity.getCardId());
        boolean isCard = cardIds.contains(memberBindRecordEntity.getCardId());
        if (!isCard) {
            throw new ServiceException("该卡不支持此课程！");
        }
        //5. 预约次数
        CourseEntity courseEntity1 = courseDao.selectById(scheduleRecordDao.selectById(reservationRecordEntity.getScheduleId()).getCourseId());
        int countReservation = reservationRecordDao.selectCount(new QueryWrapper<ReservationRecordEntity>()
                .eq("member_id", reservationRecordEntity.getMemberId())
                .eq("schedule_id", reservationRecordEntity.getScheduleId()));
        System.out.println("预约次数" + countReservation);
        if (countReservation > 0) {
            if (courseEntity1.getLimitCounts().equals("无限制")) {
            } else {
                int i = Integer.parseInt(courseEntity1.getLimitCounts());
                if (countReservation >= i) {
                    throw new ServiceException("你已超过预约次数！");
                }
            }
        }
        //取消预约次数
        ReservationRecordEntity reservationRecordEntity1 = reservationRecordDao.selectOne(new QueryWrapper<ReservationRecordEntity>()
                .eq("member_id", reservationRecordEntity.getMemberId())
                .eq("schedule_id", reservationRecordEntity.getScheduleId())
                .eq("card_id", reservationRecordEntity.getCardId())
                .eq("status", 0));
        if (reservationRecordEntity1 != null) {
            System.out.println("取消预约次数" + reservationRecordEntity1.getCancelTimes());
            boolean isOverCancelTimes = (reservationRecordEntity1.getCancelTimes() <= 300);
            if (!isOverCancelTimes) {
                throw new ServiceException("您取消预约次数过多,请选择其他课程！");
            }
        }
        //6. 提前预约时间是否被限制
        LocalDateTime classStartTime = LocalDateTime.of(scheduleRecordEntity.getStartDate(), scheduleRecordEntity.getClassTime());
        GlobalReservationSetEntity globalReservationSetEntity = globalSetDao.selectById(1);
        if (globalReservationSetEntity.getAppointmentStartMode() == 1) {//预约开始时间的模式，1：不限制会员可提前预约天数；
            if (globalReservationSetEntity.getAppointmentDeadlineMode() == 1) {//预约截止时间模式；1：不限制截止时间；
            } else if (globalReservationSetEntity.getAppointmentDeadlineMode() == 2) {//2：限制为上课前xx小时；
                LocalDateTime endTime = classStartTime.minusHours(globalReservationSetEntity.getEndHour());
                if (!LocalDateTime.now().isBefore(endTime)) {
                    throw new ServiceException("预约时间已过, 截止时间为：" + endTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                }
            } else {//3：限制为上课前xx天xx：xx（时间点）
                LocalDateTime endTime = classStartTime.minusDays(globalReservationSetEntity.getEndDay())
                        .minusHours(globalReservationSetEntity.getEndHour());
                if (!LocalDateTime.now().isBefore(endTime)) {
                    throw new ServiceException("预约时间已过, 截止时间为：" + endTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                }
            }
        } else {//2：限制天数
            LocalDateTime startTime = classStartTime.minusDays(globalReservationSetEntity.getStartDay());
            if (globalReservationSetEntity.getAppointmentDeadlineMode() == 1) {//1：不限制截止时间；
                if (!LocalDateTime.now().isAfter(startTime)) {
                    throw new ServiceException("预约时间已过！");
                }
            } else if (globalReservationSetEntity.getAppointmentDeadlineMode() == 2) {//2：限制为上课前xx小时；
                LocalDateTime endTime = classStartTime.minusHours(globalReservationSetEntity.getEndHour());
                if (!LocalDateTime.now().isAfter(startTime) && LocalDateTime.now().isBefore(endTime)) {
                    throw new ServiceException("预约时间已过, 截止时间为：" + endTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                }
            } else {//3：限制为上课前xx天xx：xx（时间点）
                LocalTime fixedTime = globalReservationSetEntity.getEndTime();
                LocalDateTime endTime = classStartTime.minusDays(globalReservationSetEntity.getEndDay())
                        .withHour(fixedTime.getHour())
                        .withMinute(fixedTime.getMinute())
                        .withSecond(fixedTime.getSecond());
                System.out.println("现在预约时间" + LocalDateTime.now());
                if (!LocalDateTime.now().isAfter(startTime) && LocalDateTime.now().isBefore(endTime)) {
                    throw new ServiceException("预约时间已过！, 截止时间为：" + endTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                }
            }
        }
        //7. 会员卡余额和次数是否足够
        //获取该会员的会员卡金额和卡次数
        Integer validCount = memberBindRecordEntity.getValidCount();
        BigDecimal receivedMoney = memberBindRecordEntity.getReceivedMoney();
        //预约所花费的次数
        Integer timesCost = courseEntity.getTimesCost() * reservationRecordEntity.getReserveNums();
        //预约所花费的金额
        BigDecimal money = courseEntity.getMoney().multiply(BigDecimal.valueOf(reservationRecordEntity.getReserveNums()));
        System.out.println("会员卡剩余的次数" + validCount);
        System.out.println("会员卡剩余的金额" + receivedMoney);
        System.out.println("预约所花费的次数" + timesCost);
        System.out.println("预约所花费的金额" + money);
        if (!(validCount >= timesCost && receivedMoney.compareTo(money) >= 0)) {
            throw new ServiceException("会员卡次数或金额不够！");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)//sql语句回滚
    public void isInfo(ReservationRecordEntity reservationRecordEntity, String startDate1) {

        ReservationRecordEntity reservationRecordEntity1 = reservationRecordDao.selectOne(new QueryWrapper<ReservationRecordEntity>()
                .eq("member_id", reservationRecordEntity.getMemberId())
                .eq("schedule_id", reservationRecordEntity.getScheduleId())
                .eq("card_id", reservationRecordEntity.getCardId()));
        System.out.println("该课程该会员的会员卡预约的记录" + reservationRecordEntity1);


        //如果该会员的会员卡预约记录为空，则新增记录，否则更新记录
        if (reservationRecordEntity1 == null) {

            //reservation_record表增加记录
            try {
                reservationRecordDao.insert(reservationRecordEntity);
            } catch (Exception e) {
                throw new ServiceException("添加预约记录失败！");
            }
            //class_record增加记录
            try {
                ClassRecordEntity classRecordEntity = new ClassRecordEntity();
                classRecordEntity.setMemberId(reservationRecordEntity.getMemberId())
                        .setCardName(reservationRecordEntity.getCardName())
                        .setScheduleId(reservationRecordEntity.getScheduleId())
                        .setNote("正常预约客户")
                        .setComment(reservationRecordEntity.getComment())
                        .setBindCardId(reservationRecordEntity.getCardId());
                classRecordDao.insert(classRecordEntity);
            } catch (Exception e) {
                throw new ServiceException("添加上课记录失败！");
            }
            //schedule_record增加预约人数
            try {
                ScheduleRecordEntity scheduleRecordEntity = scheduleRecordDao.selectById(reservationRecordEntity.getScheduleId());
                scheduleRecordEntity.setOrderNums(scheduleRecordEntity.getOrderNums() + reservationRecordEntity.getReserveNums());
                scheduleRecordDao.updateById(scheduleRecordEntity);
            } catch (Exception e) {
                throw new ServiceException("更新课程人数记录失败！");
            }
        } else {
            //判断时间是否冲突
            //isTime(reservationRecordEntity, startDate1);
            //用已存在记录, 更新状态为预约状态0
            try {
                ClassRecordEntity classRecordEntity = classRecordDao.selectOne(new QueryWrapper<ClassRecordEntity>()
                        .eq("member_id", reservationRecordEntity.getMemberId())
                        .eq("schedule_id", reservationRecordEntity.getScheduleId()));
                classRecordEntity.setReserveCheck(0);
                classRecordDao.updateById(classRecordEntity);
            } catch (Exception e) {
                throw new ServiceException("更新课程记录状态失败！");
            }
            //schedule_record增加预约人数
            try {
                ScheduleRecordEntity scheduleRecordEntity = scheduleRecordDao.selectById(reservationRecordEntity.getScheduleId());
                scheduleRecordEntity.setOrderNums(scheduleRecordEntity.getOrderNums() + reservationRecordEntity.getReserveNums());
                scheduleRecordDao.updateById(scheduleRecordEntity);
            } catch (Exception e) {
                throw new ServiceException("更新课程人数记录失败！");
            }
        }
    }

    /**
     * 目的: 判断该会员在预约课程的时间是否有冲突
     * 步骤:
     * 1. 获取前段传来的该课程日期
     * 2. 根据课程id计算出该课程的开始时间和结束时间
     * 3. 遍历该会员的所有上课记录, 排除掉自己预约的课程
     * 4. 根据课程id和日期查询当天的课程表记录, 如果不为空, 则
     *    根据会员id和课程id查询上课记录表, 判断上课记录表是否已预约, 如果已取消预约则把该课程的时间计算进去
     * 5. 遍历所有课程的时间, 判断是否有时间冲突
     */
    //////////////判断时间是否冲突/////////////////////
    public void isTime(ReservationRecordEntity reservationRecordEntity, String startDate) {

        //获取当天课程的日期
        System.out.println("isInfo===:reservationRecordEntity===>" + reservationRecordEntity);
        LocalDate date = LocalDate.parse(startDate.substring(0, 10), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        System.out.println("startDate===>" + date);

        //判断当前课程日期date只能是今天或者明天之后的日期
        if (date.isBefore(LocalDate.now())) {
            //throw new ServiceException("日期只能是今天或者明天之后的日期！");
        }

        //得到schedule_id
        Long scheduleId1 = reservationRecordEntity.getScheduleId();///////////////schedule_id
        System.out.println("课程表Id===>" + scheduleId1);

        //根据scheduleId1查询t_schedule_record表, 得到这个课程的开始时间和结束时间
        ScheduleRecordEntity scheduleRecordEntity1 = scheduleRecordDao.selectById(scheduleId1);
        System.out.println("scheduleRecordEntity===>" + scheduleRecordEntity1);
        //得到class_time
        LocalTime classTime1 = scheduleRecordEntity1.getClassTime();
        //得到course_id
        Long courseId1 = scheduleRecordEntity1.getCourseId();
        //得到duration
        Long duration1 = courseDao.selectById(courseId1).getDuration();
        //得到结束时间
        LocalTime endTime1 = classTime1.plusMinutes(duration1 + 10);
        System.out.println("该课程开始时间===>" + classTime1);
        System.out.println("该课程结束时间===>" + endTime1);
        TimeEntity courseTime = new TimeEntity(classTime1, endTime1);
        System.out.println("该课程总时长===>" + courseTime);


        //如果没有那个m,s,c查询的记录
        //得到member_id
        Long memberId = reservationRecordEntity.getMemberId();///////////////member_id
        //根据member_id查询该会员的所有预约记录
        List<ReservationRecordEntity> reservationRecordEntities = reservationRecordDao.selectList(new QueryWrapper<ReservationRecordEntity>()
                .eq("member_id", memberId));
        System.out.println("该会员的所有预约记录" + reservationRecordEntities);
        //遍历该会员所有的上课记录reservationRecordEntities
        List<TimeEntity> timeEntities = new ArrayList<>();
        for (ReservationRecordEntity re : reservationRecordEntities) {
            //得到schedule_id
            Long scheduleId = re.getScheduleId();
            //排除掉自己预约的课程
            if (scheduleId.equals(scheduleId1)) {
                continue;
            }
            System.out.println("课程表Id===>" + scheduleId);


            //根据schedule_id和date查询schedule_record表, 得到这个课程的开始时间和结束时间
            ScheduleRecordEntity scheduleRecordEntity = scheduleRecordDao.selectOne(new QueryWrapper<ScheduleRecordEntity>()
                    .eq("id", scheduleId)
                    .eq("start_date", date));
            if (scheduleRecordEntity != null) {

                //根据schedule_id和member_id查询class_record表
                ClassRecordEntity classRecordEntity1 = classRecordDao.selectOne(new QueryWrapper<ClassRecordEntity>()
                        .eq("member_id", memberId)
                        .eq("schedule_id", scheduleId));
                System.out.println("课程记录classRecordEntity1===>" + classRecordEntity1);
                if (classRecordEntity1.getReserveCheck() == 1) {//等于1, 说明已取消预约
                    continue;
                }
                System.out.println("课程表记录scheduleRecordEntity===>" + scheduleRecordEntity);
                //得到class_time
                LocalTime classTime = scheduleRecordEntity.getClassTime();
                //得到course_id
                Long courseId = scheduleRecordEntity.getCourseId();
                //得到duration
                Long duration = courseDao.selectById(courseId).getDuration();
                //得到结束时间
                LocalTime endTime = classTime.plusMinutes(duration + 10);
                TimeEntity timeEntity = new TimeEntity(classTime, endTime);
                timeEntities.add(timeEntity);
            }
        }
        System.out.println("时间排序前-timeEntities===>" + timeEntities);
        Collections.sort(timeEntities, new TimeComparator());
        System.out.println("时间排序后-timeEntities===>" + timeEntities);

        //判断是否有时间冲突
        boolean flag = ClassTimeUtil.isAdd(timeEntities, courseTime);
        if (!flag) {
            throw new ServiceException("时间冲突，请选择其它时间！!!!!!!!!!!");
        }
    }


    // 自定义比较器
    public class TimeComparator implements Comparator<TimeEntity> {
        @Override
        public int compare(TimeEntity te1, TimeEntity te2) {
            // 首先根据startTime进行排序
            int startTimeComparison = te2.getStartTime().compareTo(te1.getStartTime());
            // 如果startTime相同，则根据endTime进行排序
            if (startTimeComparison == 0) {
                return te2.getEndTime().compareTo(te1.getEndTime());
            }
            return startTimeComparison;
        }
    }


}
